package cn.geminis.crypto.core.builder;

import cn.geminis.crypto.core.util.ProviderUtils;
import cn.geminis.crypto.core.x509.Crl;
import cn.geminis.crypto.core.x509.X509Certificate;
import cn.geminis.crypto.csp.AbstractSigner;
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cms.*;

import java.util.List;
import java.util.Objects;

/**
 * @author puddi
 */
public class Pkcs7Builder {

    private CMSSignedDataGenerator signedDataGenerator;
    private SignerInfoGeneratorBuilder signerInfoGeneratorBuilder;
    private AbstractSigner signer;
    private X509Certificate signerCert;
    private CMSTypedData content;
    private boolean withData;
    private boolean authenticateAttribute = true;

    public Pkcs7Builder(AbstractSigner signer, X509Certificate signerCert) {
        signedDataGenerator = new CMSSignedDataGenerator();
        signerInfoGeneratorBuilder = new SignerInfoGeneratorBuilder(
                ProviderUtils.getDigestCalculatorProvider(),
                signatureAlgorithm -> signatureAlgorithm
        );
        this.signer = signer;
        this.signerCert = signerCert;
    }

    public Pkcs7Builder addCrls(List<Crl> crls) {
        crls.forEach(crl -> signedDataGenerator.addCRL(crl.getBcCrl()));
        return this;
    }

    public Pkcs7Builder addCertChain(List<X509Certificate> certs) {
        certs.forEach(cert -> {
            try {
                signedDataGenerator.addCertificate(new X509CertificateHolder(cert.getBcCertificate()));
            } catch (CMSException e) {
                throw new RuntimeException("添加证书链错误", e);
            }
        });
        return this;
    }

    public Pkcs7Builder setData(byte[] data) {
        content = new CMSProcessableByteArray(data);
        return this;
    }

    public Pkcs7Builder setWithData(boolean flag) {
        this.withData = flag;
        return this;
    }

    public Pkcs7Builder setAuthenticatedAttribute(boolean flag) {
        this.authenticateAttribute = !flag;
        return this;
    }

    public byte[] build() {
        try {

            var signerInfoGenerator = signerInfoGeneratorBuilder
                    .setDirectSignature(this.authenticateAttribute)
                    .build(signer.createContentSigner(),
                            new X509CertificateHolder(signerCert.getBcCertificate()));
            signedDataGenerator.addSignerInfoGenerator(signerInfoGenerator);

            if (Objects.isNull(this.content)) {
                this.content = new CMSAbsentContent();
            }

            var cmsSignedData = signedDataGenerator.generate(this.content, this.withData);
            return cmsSignedData.toASN1Structure().getEncoded(ASN1Encoding.DER);
        } catch (Exception e) {
            throw new RuntimeException("产生PKCS7格式数据错误", e);
        }
    }

}
